/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package ecodex.serviciospruebas;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

/**
 *
 * @author Ecodex6
 */
public class Utils {
    private MessageDigest md;
    private byte[] buffer, digest;
    private String hash = "";    
    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
    
    /**
     * Lee un archivo y lo regresa como cadena.
     * @param filePath Path del archivo (usado aqui solo para los archivos XML)
     * @return El archivo en una cadena.
     * @throws IOException 
     */
    public static String readFileAsString(String filePath) throws IOException{
        String comprobanteXML = new String();
        byte[] buffer = new byte[(int) new File(filePath).length()];
        BufferedInputStream f = null;
       
        try {
            f = new BufferedInputStream(new FileInputStream(filePath));
            f.read(buffer);
            comprobanteXML = new String(buffer);
            byte[] as = comprobanteXML.getBytes("UTF-8");
            comprobanteXML  = new String(as, "UTF-8");
            comprobanteXML = comprobanteXML.replace("\uFEFF", "");//Si la cadena contitene BOM se le elimina
        } 
        finally {
            if (f != null) {
                try { 
                    f.close(); 
                }
                catch (IOException ignored) {
                    System.out.print(ignored); 
                }
            }            
        }
        
        return comprobanteXML;
    }
    
    /**
     * Guarda una cadena en un archivo
     * @param xmlString Cadena a guardar
     * @param filePath Nombre del archivo de salida
     * @throws IOException 
     */
    public static void writeStringAsFile(String xmlString, String filePath) throws IOException{
        Path path = Paths.get(filePath);
        Charset charset = Charset.forName("\"UTF-8\"");
        try (BufferedWriter bufferedWriter = Files.newBufferedWriter(path, charset, StandardOpenOption.WRITE)) {
            bufferedWriter.write(xmlString, 0, xmlString.length());
        } catch (IOException x) {
            System.err.format("IOException: %s%n", x);
        }
    }
        
    /**
     * Busca y devuelve el valor de un atributo en una cadena XML pasando el nombre como parámetro
     * @param xmlString
     * @param atributo
     * @return 
     */
    public static String searchAttributeintoXML(String xmlString, String atributo){
        String attributeValue = new String();
        
        try
        {
            String xPathExpression = String.format("//@%s[1]", atributo);
            XPath xpath = XPathFactory.newInstance().newXPath();
            InputSource inputSource = new InputSource(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
            attributeValue = xpath.compile(xPathExpression).evaluate(inputSource);
        }
        catch(UnsupportedEncodingException | XPathExpressionException ex)
        {
            System.out.println(ex.getMessage());
        }

        return attributeValue;
    }    
    
    /**
     * Obtiene el nombre del nodo raíz
     * @param xmlString
     * @return 
     * @throws java.io.UnsupportedEncodingException 
     * @throws javax.xml.xpath.XPathExpressionException 
     */
    public static String getRootNodeName(String xmlString) 
            throws UnsupportedEncodingException, XPathExpressionException {
        String rootNodeName = new String();
        
        try
        {
            XPath xpath = XPathFactory.newInstance().newXPath();
            InputSource inputSource = new InputSource(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
            Node node = (Node)xpath.compile("/*[1]").evaluate(inputSource, XPathConstants.NODE);
            rootNodeName = node.getLocalName();
        }
        catch(UnsupportedEncodingException | XPathExpressionException ex)
        {
            throw ex;
        }

        return rootNodeName;        
    }
    
    /**
     * Convierte un arreglo de bytes a su representación Hexadecimal en una cadena
     * @param bytes Arreglo de bytes
     * @return Representación Hexadecimal
     */
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }
    
    /**
     * Obtiene el valor de la propiedad que se envía como parámetro
     * @param property
     * @return 
     */
    public static String getPropertyValue(String property) {
        Properties prop = new Properties();
        String propFileName = "config.properties";
        InputStream inputStream = Utils.class.getClassLoader().getResourceAsStream(propFileName);

        try {
            if (inputStream != null) {
                prop.load(inputStream);            
            } else {
                throw new FileNotFoundException("archivo de propiedades '" + propFileName + "' no fue encontrado en la ruta de clases.");
            }                
        } catch (IOException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        }        

        return prop.getProperty(property);
    }    
    
    /**
     * Genera un hash SHA1 a partir de un arreglo de bytes
     * @param as
     * @return 
     */
    public String toSHA1(byte[] as) {
        String token = "";
        try {            
            token = this.getHash(new String(as, "UTF-8"));
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        return token;
    }
    
    /**
     * Genera un hash SHA1 para la cadena enviada como parámetro
     * @param message
     * @return
     * @throws NoSuchAlgorithmException 
     */
    public String getHash(String message) throws NoSuchAlgorithmException {
        buffer = message.getBytes();
        md = MessageDigest.getInstance("SHA1");
        md.update(buffer);
        digest = md.digest();

        for(byte aux : digest) {
            int b = aux & 0xff;
            if (Integer.toHexString(b).length() == 1) hash += "0";
            hash += Integer.toHexString(b);
        }

        return hash;
    }    
}
